from bcat.gtp.serde.error import ExpectTypeError, ValueEmptyError, ExpectLengthError


class AssertOrRaise(object):
    class Length(object):
        def __init__(self, parent, real_length):
            self.__parent = parent
            self.__length = real_length

        def equal_to(self, expect):
            if self.__length != expect:
                raise ExpectLengthError(expect, self.__length)
            return self.__parent
        def less_than(self, expect):
            if self.__length >= expect:
                raise ExpectLengthError(expect, self.__length)
            return self.__parent
        def greater_than(self, expect):
            if self.__length <= expect:
                raise ExpectLengthError(expect, self.__length)
            return self.__parent
        def less_equal(self, expect):
            if self.__length > expect:
                raise ExpectLengthError(expect, self.__length)
            return self.__parent
        def greater_equal(self, expect):
            if self.__length < expect:
                raise ExpectLengthError(expect, self.__length)
            return self.__parent

    def __init__(self, v):
        self.__v = v

    def not_none(self, msg=""):
        if self.__v is None:
            raise ValueEmptyError(f"assert not none:{msg}")
        return self

    def is_types(self, types=()):
        if not isinstance(self.__v, types):
            raise ExpectTypeError.from_real_value(types, self.__v)
        return self

    def is_type(self, tp):
        if not isinstance(self.__v, tp):
            raise ExpectTypeError.from_real_value(tp, self.__v)
        return self

    def length(self):
        return AssertOrRaise.Length(self, len(self.__v))

import unittest
class TestAssertOrRaise(unittest.TestCase):
    def test_assert_raise(self):
        bs = None
        with self.assertRaises(ValueEmptyError):
            AssertOrRaise(bs).not_none(bs)

        bs = "helloworld"
        AssertOrRaise(bs).not_none(bs)
        AssertOrRaise(bs).not_none(bs).is_type(str)
        AssertOrRaise(bs).not_none(bs).is_type(str).is_types((str,))

        with self.assertRaises(ExpectTypeError):
            AssertOrRaise(bs).is_types((bytes, bytearray, memoryview))
        
        bs = b'aaaa'
        AssertOrRaise(bs) \
            .not_none(bs) \
            .is_types((bytes, bytearray, memoryview))

    def test_not_none_success(self):
        AssertOrRaise(1).not_none()

    def test_not_none_failure(self):
        with self.assertRaises(ValueEmptyError):
            AssertOrRaise(None).not_none("值不能为空")

    def test_is_types_success(self):
        value = 123
        AssertOrRaise(value).is_types((int,))

    def test_is_types_failure(self):
        with self.assertRaises(ExpectTypeError):
            AssertOrRaise("abc").is_types((int,))

    def test_is_type_success(self):
        AssertOrRaise(10).is_type(int)

    def test_is_type_failure(self):
        with self.assertRaises(ExpectTypeError):
            AssertOrRaise("hello").is_type(int)

    def test_length(self):
        AssertOrRaise("hello").length().equal_to(5)
        with self.assertRaises(ExpectLengthError):
            AssertOrRaise("hello").length().equal_to(6)

        AssertOrRaise("hello").length().less_than(10)
        with self.assertRaises(ExpectLengthError):
            AssertOrRaise("hello").length().less_than(2)

        AssertOrRaise("hello").length().greater_than(2)
        with self.assertRaises(ExpectLengthError):
            AssertOrRaise("hello").length().greater_than(10)

        AssertOrRaise("hello").length().less_equal(10)
        with self.assertRaises(ExpectLengthError):
            AssertOrRaise("hello").length().less_equal(2)

        AssertOrRaise("hello").length().greater_equal(2)
        with self.assertRaises(ExpectLengthError):
            AssertOrRaise("hello").length().greater_equal(10)
